/**
******************************************************************************
* @file    			DHCP.c
* @author  			WIZnet Software Team 
* @version 			V1.0
* @date    			2015-02-14
* @brief   			DHCP	Client
* @attention		使用DHCP配置IP地址需要定义
******************************************************************************
*/
#include <stdio.h>
#include <string.h>	

#include "W5500_Driver.h"
#include "socket.h"

#include "dhcp.h"
#include "utility.h"

#pragma region //================字段======================
uint8*   SRC_MAC_ADDR   = EXTERN_DHCP_MAC;				/*本地MAC地址*/
uint8*   GET_SN_MASK    = EXTERN_DHCP_SN;					/*从DHCP服务器获取到的子网掩码*/
uint8*   GET_GW_IP      = EXTERN_DHCP_GW;					/*从DHCP服务器获取到的网关地址*/
uint8*   GET_DNS_IP     = EXTERN_DHCP_DNS;				/*从DHCP服务器获取到的DNS服务器地址*/
uint8*   DHCP_HOST_NAME = EXTERN_DHCP_NAME;   		/*主机名*/
uint8*   GET_SIP        = EXTERN_DHCP_SIP;				/*从DHCP服务器获取到的本机IP*/
uint8    DHCP_SIP[4] = {0,};											/*已发现的DNS服务器地址*/
uint8    DHCP_REAL_SIP[4] = {0,}; 								/*从DHCP列表中选择使用的DHCP服务器*/
uint8    OLD_SIP[4];        											/*最初获取到的IP地址*/

uint8		dhcp_state       = STATE_DHCP_READY;       /*DHCP客户端状态*/
uint8		dhcp_retry_count = 0;                      /*DHCP重试次数*/
uint8		DHCP_timeout     = 0;                      /*DHCP超时标志位*/
uint32  dhcp_lease_time;							/*租约时间*/
uint32	next_dhcp_time  = 0;						/*DHCP超时时间ms*/
uint32	start_dhcp_time  = 0;                   	/*DHCP开始时刻ms*/

uint8 Conflict_flag = 0;
uint32  DHCP_XID        = DEFAULT_XID;				
uint8 EXTERN_DHCPBUF[1024];
RIP_MSG*  pRIPMSG = (RIP_MSG*)EXTERN_DHCPBUF;			/*DHCP消息指针*/

#pragma endregion


#pragma region //==============全局变量=================
uint8   dhcp_ok   = 0; /*=1: dhcp成功获取IP*/
DHCP_Get DHCP_GET;

#pragma endregion


#pragma region //=================私有函数====================
/**
*@brief		DHCP定时初始化
*@param		无
*@return	无
*/
static void reset_DHCP_time(void)
{
	start_dhcp_time = HAL_GetTick();	//	dhcp_time = 0;
	next_dhcp_time = start_dhcp_time + DHCP_WAIT_TIME * 1000;
	dhcp_retry_count = 0;
}
/**	
*@brief	 	DHCP 定时器操作
*@param		无
*@return	无
*/
//void DHCP_timer_handler(void)
//{
//	if (dhcp_tick_cnt++ > 1000)
//	{
//		dhcp_tick_cnt = 0;
//		dhcp_time++;
//	}	
//}
//获得dhcp时间,单位:秒
static uint32_t get_dhcp_time_s(void)
{
	return (HAL_GetTick() - start_dhcp_time) / 1000;///1000ms->[s]
}

/**
*@brief		发送DISCOVER信息给DHCP服务器
*@param		无
*@return	无
*/
static void send_DHCP_DISCOVER(void)
{
	uint8 ip[4] = {255,255,255,255};
	uint16 i=0;
	//the host name modified
	uint8 host_name[12];
	//*((uint32*)DHCP_SIP)=0;
	//*((uint32*)DHCP_REAL_SIP)=0;
	memset((void*)pRIPMSG,0,sizeof(RIP_MSG));				/*清空pRIPMSG的 sizeof(RIP_MSG)	个空间*/
//	for (int i = 0; i < sizeof(RIP_MSG); i++)
//	{
//		EXTERN_DHCPBUF[i] = 0;
//	}
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	pRIPMSG->flags =htons(DHCP_FLAGSBROADCAST);
	pRIPMSG->chaddr[0] = SRC_MAC_ADDR[0];
	pRIPMSG->chaddr[1] = SRC_MAC_ADDR[1];
	pRIPMSG->chaddr[2] = SRC_MAC_ADDR[2];
	pRIPMSG->chaddr[3] = SRC_MAC_ADDR[3];
	pRIPMSG->chaddr[4] = SRC_MAC_ADDR[4];
	pRIPMSG->chaddr[5] = SRC_MAC_ADDR[5];    
	
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE& 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = DHCP_DISCOVER;
	
	/*Client identifier*/
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];
	
	// host name
	pRIPMSG->OPT[i++] = hostName;
	// set the host name
	sprintf((char*)host_name,"%.4s-%02X%02X%02X",DEVICE_ID,SRC_MAC_ADDR[3],SRC_MAC_ADDR[4],SRC_MAC_ADDR[5]);
	
	
	pRIPMSG->OPT[i++] = (uint8)strlen((char*)host_name);
	
	strcpy((char*)(&(pRIPMSG->OPT[i])),(char*)host_name);
	
	
	i+=(uint16)strlen((char*)host_name);	
	
	pRIPMSG->OPT[i++] = dhcpParamRequest;
	pRIPMSG->OPT[i++] = 0x06;
	pRIPMSG->OPT[i++] = subnetMask;
	pRIPMSG->OPT[i++] = routersOnSubnet;
	pRIPMSG->OPT[i++] = dns;
	pRIPMSG->OPT[i++] = domainName;
	pRIPMSG->OPT[i++] = dhcpT1value;
	pRIPMSG->OPT[i++] = dhcpT2value;
	pRIPMSG->OPT[i++] = endOption;
	
	/* send broadcasting packet */
	//printf("send dhcp discover %s\r\n",EXTERN_DHCPBUF);
	//for(uint8 i=0; i<3; i++)
	//Delay_ms(800);
	sendto(SOCK_DHCP, (uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);	
	
	PRINT("sent DHCP_DISCOVER\r\n");
}

/**
*@brief		将请求消息发送到DHCP服务器
*@param		无
*@return	无
*/
static void send_DHCP_REQUEST(void)
{
	uint8  ip[4];
	uint16 i = 0;
	//uint16 len=0;
	uint8  host_name[12];
	
//	memset((void*)pRIPMSG, 0, sizeof(RIP_MSG));
	for (int i = 0; i < sizeof(RIP_MSG); i++)
	{
		EXTERN_DHCPBUF[i] = 0;
	}
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	
	if (dhcp_state < STATE_DHCP_LEASED)
		pRIPMSG->flags = htons(DHCP_FLAGSBROADCAST);
	else
	{
		pRIPMSG->flags = 0; // For Unicast
		memcpy(pRIPMSG->ciaddr, GET_SIP, 4);
	}		
	
	memcpy(pRIPMSG->chaddr, SRC_MAC_ADDR, 6);
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE & 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = DHCP_REQUEST;
	
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];	
	
	
	if (dhcp_state < STATE_DHCP_LEASED)
	{
		pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
		pRIPMSG->OPT[i++] = 0x04;
		pRIPMSG->OPT[i++] = GET_SIP[0];
		pRIPMSG->OPT[i++] = GET_SIP[1];
		pRIPMSG->OPT[i++] = GET_SIP[2];
		pRIPMSG->OPT[i++] = GET_SIP[3];
		
		pRIPMSG->OPT[i++] = dhcpServerIdentifier;
		pRIPMSG->OPT[i++] = 0x04;
		pRIPMSG->OPT[i++] = DHCP_SIP[0];
		pRIPMSG->OPT[i++] = DHCP_SIP[1];
		pRIPMSG->OPT[i++] = DHCP_SIP[2];
		pRIPMSG->OPT[i++] = DHCP_SIP[3];
	}
	
	// host name
	pRIPMSG->OPT[i++] = hostName;
	//set the host name
	sprintf((char*)host_name, (char*)"%.4s-%02X%02X%02X", DEVICE_ID, SRC_MAC_ADDR[3], SRC_MAC_ADDR[4], SRC_MAC_ADDR[5]);
	pRIPMSG->OPT[i++] = (uint8)strlen((char*)host_name);	
	strcpy((char*)&(pRIPMSG->OPT[i]), (char*)host_name);
	i += strlen((char*)host_name);
		
	pRIPMSG->OPT[i++] = dhcpParamRequest;
	pRIPMSG->OPT[i++] = 0x08;
	pRIPMSG->OPT[i++] = subnetMask;
	pRIPMSG->OPT[i++] = routersOnSubnet;
	pRIPMSG->OPT[i++] = dns;
	pRIPMSG->OPT[i++] = domainName;
	pRIPMSG->OPT[i++] = dhcpT1value;
	pRIPMSG->OPT[i++] = dhcpT2value;
	pRIPMSG->OPT[i++] = performRouterDiscovery;
	pRIPMSG->OPT[i++] = staticRoute;
	pRIPMSG->OPT[i++] = endOption;
	
	/* send broadcasting packet */
	if (dhcp_state < STATE_DHCP_LEASED) memset(ip, 0xFF, 4);
	else 
		memcpy(ip, DHCP_SIP, 4);
	sendto(SOCK_DHCP, (const uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
	PRINT("sent DHCP_REQUEST\r\n");
}

/**	 
*@brief	 	解析获得的DHCP消息
*@param		length:解析消息长度
*@return	0：解析失败  其他：解析成功
*/
static uint8 parseDHCPMSG(uint16 length)
{
	uint8  svr_addr[6];
	uint16 svr_port;
	uint16 len;
	uint8  * p;
	uint8  * e;
	uint8  type;
	uint8  opt_len = 0;
	
	len = recvfrom(SOCK_DHCP, (uint8 *)pRIPMSG, length, svr_addr, &svr_port);
	
	PRINT("DHCP_SIP:%u.%u.%u.%u\r\n", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
	PRINT("DHCP_RIP:%u.%u.%u.%u\r\n", DHCP_REAL_SIP[0], DHCP_REAL_SIP[1], DHCP_REAL_SIP[2], DHCP_REAL_SIP[3]);
	PRINT("svr_addr:%u.%u.%u.%u\r\n", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
	
	if (pRIPMSG->op != DHCP_BOOTREPLY || svr_port != DHCP_SERVER_PORT)
	{
		PRINT("DHCP : NO DHCP MSG\r\n");
		return 0;
	}
	if (memcmp(pRIPMSG->chaddr, SRC_MAC_ADDR, 6) != 0 || pRIPMSG->xid != htonl(DHCP_XID))
	{
		PRINT("No My DHCP Message. This message is ignored.\r\n");
		PRINT("\tSRC_MAC_ADDR(%02X.%02X.%02X.", SRC_MAC_ADDR[0], SRC_MAC_ADDR[1], SRC_MAC_ADDR[2]);
		PRINT("%02X.%02X.%02X)", SRC_MAC_ADDR[3], SRC_MAC_ADDR[4], SRC_MAC_ADDR[5]);
		PRINT(", pRIPMSG->chaddr(%02X.%02X.%02X.", (char)pRIPMSG->chaddr[0], (char)pRIPMSG->chaddr[1], (char)pRIPMSG->chaddr[2]);
		PRINT("%02X.%02X.%02X)", pRIPMSG->chaddr[3], pRIPMSG->chaddr[4], pRIPMSG->chaddr[5]);
		PRINT("\tpRIPMSG->xid(%08X), DHCP_XID(%08X)", pRIPMSG->xid, (DHCP_XID));
		PRINT("\tpRIMPMSG->yiaddr:%d.%d.%d.%d\r\n", pRIPMSG->yiaddr[0], pRIPMSG->yiaddr[1], pRIPMSG->yiaddr[2], pRIPMSG->yiaddr[3]);
		return 0;
	}
	
	if (*((uint32*)DHCP_SIP) != 0x00000000)
	{
		if (*((uint32*)DHCP_REAL_SIP) != *((uint32*)svr_addr) && 
		*((uint32*)DHCP_SIP) != *((uint32*)svr_addr)) 
		{
			PRINT("Another DHCP sever send a response message. This is ignored.\r\n");
			PRINT("\tIP:%u.%u.%u.%u\r\n", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
			return 0;								
		}
	}	
	memcpy(GET_SIP, pRIPMSG->yiaddr, 4);	
	PRINT("DHCP MSG received\r\n");
	PRINT("yiaddr : %u.%u.%u.%u\r\n", GET_SIP[0], GET_SIP[1], GET_SIP[2], GET_SIP[3]);
	
	type = 0;
	p = (uint8 *)(&pRIPMSG->op);
	p = p + 240;
	e = p + (len - 240);
	PRINT("p : %08X  e : %08X  len : %d\r\n", (unsigned int)p, (unsigned int)e, len);
	while (p < e) 
	{
		switch (*p++) 
		{
		case endOption :
			return type;
		
		case padOption :
			break;
			
		case dhcpMessageType :
			opt_len = *p++;
			type = *p;
			PRINT("dhcpMessageType : %02X\r\n", type);
			break;
			
		case subnetMask :
			opt_len = * p++;
			memcpy(GET_SN_MASK, p, 4);
			PRINT("subnetMask : ");
			PRINT("%u.%u.%u.%u\r\n", GET_SN_MASK[0], GET_SN_MASK[1], GET_SN_MASK[2], GET_SN_MASK[3]);
			break;
			
		case routersOnSubnet :
			opt_len = *p++;
			memcpy(GET_GW_IP, p, 4);
			PRINT("routersOnSubnet : ");
			PRINT("%u.%u.%u.%u\r\n", GET_GW_IP[0], GET_GW_IP[1], GET_GW_IP[2], GET_GW_IP[3]);
			break;
			
		case dns :
			opt_len = *p++;
			memcpy(GET_DNS_IP, p, 4);
			break;
			
		case dhcpIPaddrLeaseTime :
			opt_len = *p++;
			dhcp_lease_time = ntohl(*((uint32*)p));
			PRINT("dhcpIPaddrLeaseTime : %d\r\n", dhcp_lease_time);
			break;
			
		case dhcpServerIdentifier :
			opt_len = *p++;
			PRINT("DHCP_SIP : %u.%u.%u.%u\r\n", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
			if (*((uint32*)DHCP_SIP) == 0 || 
			*((uint32*)DHCP_REAL_SIP) == *((uint32*)svr_addr) || 
			*((uint32*)DHCP_SIP) == *((uint32*)svr_addr))
			{
				memcpy(DHCP_SIP, p, 4);
				memcpy(DHCP_REAL_SIP, svr_addr, 4); // Copy the real ip address of my DHCP server
				PRINT("My dhcpServerIdentifier : ");
				PRINT("%u.%u.%u.%u\r\n", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
				PRINT("My DHCP server real IP address : ");
				PRINT("%u.%u.%u.%u\r\n", DHCP_REAL_SIP[0], DHCP_REAL_SIP[1], DHCP_REAL_SIP[2], DHCP_REAL_SIP[3]);
			}
			else
			{
				PRINT("Another dhcpServerIdentifier : \r\n");
				PRINT("\tMY(%u.%u.%u.%u) ", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
				PRINT("Another(%u.%u.%u.%u)\r\n", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
			}
			break;
				
		default :
			opt_len = *p++;
			PRINT("opt_len : %u\r\n", opt_len);
			break;
		} // switch
		p += opt_len;
	} // while	
	return 0;
}

/**	
*@brief	 	检查DHCP请求释放超时
*@param		无
*@return	无
*/
static void check_DHCP_Timeout(void)
{
	if (dhcp_retry_count < MAX_DHCP_RETRY) 
	{
		if (HAL_GetTick() > next_dhcp_time) 
		{
			start_dhcp_time = HAL_GetTick(); //dhcp_time = 0;
			next_dhcp_time = start_dhcp_time + DHCP_WAIT_TIME * 1000;
			dhcp_retry_count++;
			switch (dhcp_state) 
			{
			case STATE_DHCP_DISCOVER :
				PRINT("<<timeout>> state : STATE_DHCP_DISCOVER\r\n");
				send_DHCP_DISCOVER();
				break;
				
			case STATE_DHCP_REQUEST :
				PRINT("<<timeout>> state : STATE_DHCP_REQUEST\r\n");
				send_DHCP_REQUEST();
				break;		
				
			case STATE_DHCP_REREQUEST :
				PRINT("<<timeout>> state : STATE_DHCP_REREQUEST\r\n");
				send_DHCP_REQUEST();
				break;
				
			default :
				break;
			}
		}
	} 
	else 
	{
		reset_DHCP_time();
		DHCP_timeout = 1;
	
		send_DHCP_DISCOVER();
		dhcp_state = STATE_DHCP_DISCOVER;
		PRINT("timeout : state : STATE_DHCP_DISCOVER\r\n");
	}
}

/**
*@brief		发送释放消息
*@param		msgtype:是否为7
*@return	无
*/
static void send_DHCP_RELEASE_DECLINE(char msgtype)
{
	uint16 i = 0;
	uint8  ip[4];
	
//	memset((void*)pRIPMSG, 0, sizeof(RIP_MSG));
	for (int i = 0; i < sizeof(RIP_MSG); i++)
	{
		EXTERN_DHCPBUF[i] = 0;
	}
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	pRIPMSG->flags = 0; // DHCP_FLAGSBROADCAST;
	
	memcpy(pRIPMSG->chaddr, SRC_MAC_ADDR, 6);
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE & 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = ((!msgtype) ? DHCP_RELEASE : DHCP_DECLINE);
	
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];	
	
	pRIPMSG->OPT[i++] = dhcpServerIdentifier;
	pRIPMSG->OPT[i++] = 0x04;
	pRIPMSG->OPT[i++] = DHCP_SIP[0];
	pRIPMSG->OPT[i++] = DHCP_SIP[1];
	pRIPMSG->OPT[i++] = DHCP_SIP[2];
	pRIPMSG->OPT[i++] = DHCP_SIP[3];
	
	if (msgtype)
	{
		pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
		pRIPMSG->OPT[i++] = 0x04;
		pRIPMSG->OPT[i++] = GET_SIP[0];
		pRIPMSG->OPT[i++] = GET_SIP[1];
		pRIPMSG->OPT[i++] = GET_SIP[2];
		pRIPMSG->OPT[i++] = GET_SIP[3];		
		PRINT("sent DHCP_DECLINE\r\n");
	}
	else
	{
		PRINT("sent DHCP_RELEASE\r\n");
	}
	
	pRIPMSG->OPT[i++] = endOption;	
	
	
	if (msgtype) memset(ip, 0xFF, 4);
	else 
		memcpy(ip, DHCP_SIP, 4);
	//printf("send dhcp decline\r\n");
	sendto(SOCK_DHCP, (uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}
/**	
*@brief	  检查获取的IP是否冲突
*@param		无
*@return	无
*/
static uint8 check_leasedIP(void)
{
	PRINT("<Check the IP Conflict %d.%d.%d.%d: ", GET_SIP[0], GET_SIP[1], GET_SIP[2], GET_SIP[3]);
	// sendto is complete. that means there is a node which has a same IP.
	if (sendto(SOCK_DHCP, (const uint8*)"CHECK_IP_CONFLICT", 17, GET_SIP, 5000))
	{
		PRINT(" Conflict>\r\n");
		send_DHCP_RELEASE_DECLINE(1);
		return 0;
	}
	PRINT(" No Conflict>\r\n");
	return 1;
}
#pragma endregion

#pragma region //================方法API====================
/*
********************************************************************************
** 描述: 初始化DHCP客户端,软复位了w5500寄存器
********************************************************************************/
void init_dhcp_client(void)
{
	uint8 ip_0[4]={0,};
	DHCP_XID = DEFAULT_XID;//0x12345678;
	memset(OLD_SIP,0,sizeof(OLD_SIP));
	memset(DHCP_SIP,0,sizeof(DHCP_SIP));
	memset(DHCP_REAL_SIP,0,sizeof(GET_SN_MASK));
	
	/*clear ip setted flag */
	iinchip_init();
	setSUBR(ip_0);
	setGAR(ip_0);
	setSIPR(ip_0);
	PRINT("mac=%02x:%02x:%02x:%02x:%02x:%02x\r\n", SRC_MAC_ADDR[0], SRC_MAC_ADDR[1], SRC_MAC_ADDR[2], SRC_MAC_ADDR[3], SRC_MAC_ADDR[4], SRC_MAC_ADDR[5]); 
	
	dhcp_state = STATE_DHCP_READY;
	PRINT("init_dhcp_client:%u\r\n", SOCK_DHCP);
}

/*
********************************************************************************
** 描述: 检查DHCP状态
** 返回: DHCP_RET_NONE: 未获取到IP地址
**      DHCP_RET_TIMEOUT: 超时
**      DHCP_RET_UPDATE: 获取成功
**      DHCP_RET_CONFLICT:IP地址冲突
********************************************************************************/
uint8 check_DHCP_state(SOCKET s)  // s: socket序数
{
	uint16 len; /*定义一个表示接收数据大小变量*/
	uint8  type; /*定义一个表示接收封包类型变量*/
	
	type = 0;
	if (getSn_SR(s) != SOCK_CLOSED)             /*socket处于打开状态*/
	{
		if ((len = getSn_RX_RSR(s)) > 0)		/*接收到数据*/
		{
			type = parseDHCPMSG(len); /*解析收到的封包类型*/
		}
	}
	else										/*socket处于关闭状态，重新初始化socket*/
	{
		if (dhcp_state == STATE_DHCP_READY)
		{
			//init_dhcp_client();
			PRINT("state : STATE_DHCP_READY\r\n");
		}	
		if (!socket(SOCK_DHCP, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00))/*初始化socket和端口*/
		{
			PRINT("Fail to create the DHCPC_SOCK(%u)\r\n", SOCK_DHCP);
			return DHCP_RET_ERR;				/*socket初始化错误*/
		}
	}
	switch (dhcp_state)
	{
	case STATE_DHCP_READY:						/*DHCP初始化状态*/
		DHCP_timeout = 0; /*DHCP超时标志设置为1*/
		reset_DHCP_time(); /*复位超时时间*/
		send_DHCP_DISCOVER(); /*发送DISCOVER包*/
//		DHCP_timer = 0; /*set_timer0(DHCP_timer_handler);  */ 	
		dhcp_state = STATE_DHCP_DISCOVER; /*DHCP的DISCOVER状态*/
		break;	 
  
	case STATE_DHCP_DISCOVER:
		if (type == DHCP_OFFER) 
		{
			reset_DHCP_time(); /*复位超时时间*/
			send_DHCP_REQUEST(); /*发送REQUEST包*/
			dhcp_state = STATE_DHCP_REQUEST;
			PRINT("state : STATE_DHCP_REQUEST\r\n");
		}
		else 
			check_DHCP_Timeout(); /*检查是否超时*/
		break;
		
	case STATE_DHCP_REQUEST :					/*DHCP的REQUEST状态*/
		if (type == DHCP_ACK) 					/*接收到DHCP服务器回应的off封包*/
		{
			reset_DHCP_time();
			if (check_leasedIP()) 
			{
				PRINT("state : STATE_DHCP_LEASED\r\n");
				dhcp_state = STATE_DHCP_LEASED;
				return DHCP_RET_UPDATE;
			} 
			else 
			{
				PRINT("state : STATE_DHCP_DISCOVER\r\n");
				dhcp_state = STATE_DHCP_DISCOVER;
				return DHCP_RET_CONFLICT;
			}
		}	
		else if(type == DHCP_NAK) 
		{
			reset_DHCP_time(); /*复位超时时间*/
			dhcp_state = STATE_DHCP_DISCOVER;
			PRINT("state : STATE_DHCP_DISCOVER\r\n");
		}
		else 
			check_DHCP_Timeout(); /*检查是否超时*/
		break;
			
	case STATE_DHCP_LEASED :
		if ((dhcp_lease_time != 0xffffffff) && (get_dhcp_time_s() > (dhcp_lease_time / 2))) 
		{
			type = 0;
			memcpy(OLD_SIP, GET_SIP, 4);
			DHCP_XID++;
			send_DHCP_REQUEST();
			dhcp_state = STATE_DHCP_REREQUEST;
			PRINT("state : STATE_DHCP_REREQUEST\r\n");
			reset_DHCP_time();
		}
		break;
	case STATE_DHCP_REREQUEST :
		if (type == DHCP_ACK) 
		{
			if (memcmp(OLD_SIP, GET_SIP, 4) != 0)	
			{
				PRINT("The IP address from the DHCP server is updated.\r\n");
				PRINT("OLD_SIP=%u.%u.%u.%u", OLD_SIP[0], OLD_SIP[1], OLD_SIP[2], OLD_SIP[3]);
				PRINT("GET_SIP=%u.%u.%u.%u\r\n", GET_SIP[0], GET_SIP[1], GET_SIP[2], GET_SIP[3]);
				return DHCP_RET_UPDATE;
			}
			PRINT("state : STATE_DHCP_LEASED : same IP\r\n");
			reset_DHCP_time();
			dhcp_state = STATE_DHCP_LEASED;
		} 
		else if (type == DHCP_NAK) 
		{
			reset_DHCP_time();
			dhcp_state = STATE_DHCP_DISCOVER;
			PRINT("state : STATE_DHCP_DISCOVER\r\n");
		} 
		else 
			check_DHCP_Timeout();
		break;
			
	default :
		dhcp_state = STATE_DHCP_READY;
		break;
	}
	if (DHCP_timeout == 1)
	{
		//kill_timer0(DHCP_timer);
		dhcp_state = STATE_DHCP_READY;
		return DHCP_RET_TIMEOUT;
	}
	return DHCP_RET_NONE;
}

/*
********************************************************************************
** 描述: 执行DHCP Client, 如果获得IP地址dhcp_ok = 1. 主程序要设置IP配置方法为DHCP并周期调用该方法.
********************************************************************************/
void do_dhcp(void)
{
	uint8 dhcpret = 0;
//	ip_from = IP_FROM_DHCP; /*IP配置方法选择为DHCP*/
	
	if (Conflict_flag == 1) /*如果ip地址发生冲突*/
	{
		init_dhcp_client(); /*初始化DHCP客户端*/ 
		Conflict_flag = 0;
	}
	
	dhcpret = check_DHCP_state(SOCK_DHCP); /*获取DHCP服务状态*/
	
	switch (dhcpret)
	{
	case DHCP_RET_NONE:                 /*IP地址获取不成功*/ 
		break;
		
	case DHCP_RET_TIMEOUT:              /*IP地址获取超时*/ 
		break;
		
	case DHCP_RET_UPDATE:				/*成功获取到IP地址*/ 
		dhcp_ok = 1;                  
		set_w5500_ip(); /*将获取到的IP地址写入W5500寄存器*/ 
		PRINT(" 已从DHCP服务器成功获得IP地址\r\n");
		break;
		
	case DHCP_RET_CONFLICT:             /*IP地址获取冲突*/ 
		PRINT(" 从DHCP获取IP地址失败\r\n");
		dhcp_state = STATE_DHCP_READY; 
		PRINT(" 重试中\r\n");
		dhcp_ok = 0; 
		break;     

	default:
		break;
	}
}
#pragma endregion

	


